package com.kexilo.logging.properties;

import java.time.Duration;
import java.util.ArrayList;
import java.util.List;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;

import jakarta.validation.Valid;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;

/**
 * 日志插件配置属性
 * 提供完善的配置选项和IDE智能提示
 * 
 * @author Kexilo
 */
@ConfigurationProperties(prefix = "kexilo.plugin.logging")
public class LoggingProperties {
    
    /**
     * 日志处理模式
     */
    public enum LoggingMode {
        SYNC,    // 同步处理
        ASYNC,   // 异步处理
        BATCH    // 批处理
    }
    
    /**
     * 是否启用日志插件
     */
    private boolean enabled = true;
    
    /**
     * 日志处理模式
     */
    private LoggingMode mode = LoggingMode.ASYNC;
    
    /**
     * 是否启用切面日志
     */
    private boolean aspectEnabled = true;
    
    /**
     * 排除的URL模式
     */
    private List<String> excludeUrls = new ArrayList<>();
    
    /**
     * 排除的类模式
     */
    private List<String> excludeClasses = new ArrayList<>();
    
    /**
     * 排除的方法模式
     */
    private List<String> excludeMethods = new ArrayList<>();
    
    /**
     * 数据库配置
     */
    @Valid
    @NestedConfigurationProperty
    private DatabaseProperties database = new DatabaseProperties();
    
    /**
     * 文件配置
     */
    @Valid
    @NestedConfigurationProperty
    private FileProperties file = new FileProperties();
    
    /**
     * 异步配置
     */
    @Valid
    @NestedConfigurationProperty
    private AsyncProperties async = new AsyncProperties();
    
    /**
     * 缓存配置
     */
    @Valid
    @NestedConfigurationProperty
    private CacheProperties cache = new CacheProperties();
    
    /**
     * 数据库配置属性
     */
    public static class DatabaseProperties {
        /**
         * 是否启用数据库存储
         */
        private boolean enabled = true;
        
        /**
         * 数据库表名
         */
        @NotBlank(message = "数据库表名不能为空")
        private String tableName = "sys_oper_log";
        
        /**
         * 批处理大小
         */
        @Min(value = 1, message = "批处理大小必须大于0")
        private int batchSize = 100;
        
        /**
         * 刷新间隔
         */
        private Duration flushInterval = Duration.ofSeconds(5);
        
        /**
         * 连接超时
         */
        private Duration connectionTimeout = Duration.ofSeconds(30);
        
        /**
         * 是否启用事务
         */
        private boolean transactionEnabled = true;
        
        // Getters and Setters
        public boolean isEnabled() { return enabled; }
        public void setEnabled(boolean enabled) { this.enabled = enabled; }
        
        public String getTableName() { return tableName; }
        public void setTableName(String tableName) { this.tableName = tableName; }
        
        public int getBatchSize() { return batchSize; }
        public void setBatchSize(int batchSize) { this.batchSize = batchSize; }
        
        public Duration getFlushInterval() { return flushInterval; }
        public void setFlushInterval(Duration flushInterval) { this.flushInterval = flushInterval; }
        
        public Duration getConnectionTimeout() { return connectionTimeout; }
        public void setConnectionTimeout(Duration connectionTimeout) { this.connectionTimeout = connectionTimeout; }
        
        public boolean isTransactionEnabled() { return transactionEnabled; }
        public void setTransactionEnabled(boolean transactionEnabled) { this.transactionEnabled = transactionEnabled; }
    }
    
    /**
     * 文件配置属性
     */
    public static class FileProperties {
        /**
         * 是否启用文件存储
         */
        private boolean enabled = false;
        
        /**
         * 文件路径
         */
        private String path = "./logs/";
        
        /**
         * 文件名
         */
        private String filename = "operation.log";
        
        /**
         * 最大文件大小
         */
        private String maxFileSize = "10MB";
        
        /**
         * 保留历史文件数量
         */
        @Min(value = 1, message = "保留历史文件数量必须大于0")
        private int maxHistory = 30;
        
        /**
         * 是否压缩历史文件
         */
        private boolean compress = true;
        
        // Getters and Setters
        public boolean isEnabled() { return enabled; }
        public void setEnabled(boolean enabled) { this.enabled = enabled; }
        
        public String getPath() { return path; }
        public void setPath(String path) { this.path = path; }
        
        public String getFilename() { return filename; }
        public void setFilename(String filename) { this.filename = filename; }
        
        public String getMaxFileSize() { return maxFileSize; }
        public void setMaxFileSize(String maxFileSize) { this.maxFileSize = maxFileSize; }
        
        public int getMaxHistory() { return maxHistory; }
        public void setMaxHistory(int maxHistory) { this.maxHistory = maxHistory; }
        
        public boolean isCompress() { return compress; }
        public void setCompress(boolean compress) { this.compress = compress; }
    }
    
    /**
     * 异步配置属性
     */
    public static class AsyncProperties {
        /**
         * 是否启用异步处理
         */
        private boolean enabled = true;
        
        /**
         * 核心线程池大小
         */
        @Min(value = 1, message = "核心线程池大小必须大于0")
        private int corePoolSize = 2;
        
        /**
         * 最大线程池大小
         */
        @Min(value = 1, message = "最大线程池大小必须大于0")
        private int maxPoolSize = 10;
        
        /**
         * 队列容量
         */
        @Min(value = 1, message = "队列容量必须大于0")
        private int queueCapacity = 200;
        
        /**
         * 线程名前缀
         */
        private String threadNamePrefix = "kexilo-logging-";
        
        /**
         * 线程存活时间
         */
        private Duration keepAliveTime = Duration.ofSeconds(60);
        
        /**
         * 是否允许核心线程超时
         */
        private boolean allowCoreThreadTimeOut = false;
        
        // Getters and Setters
        public boolean isEnabled() { return enabled; }
        public void setEnabled(boolean enabled) { this.enabled = enabled; }
        
        public int getCorePoolSize() { return corePoolSize; }
        public void setCorePoolSize(int corePoolSize) { this.corePoolSize = corePoolSize; }
        
        public int getMaxPoolSize() { return maxPoolSize; }
        public void setMaxPoolSize(int maxPoolSize) { this.maxPoolSize = maxPoolSize; }
        
        public int getQueueCapacity() { return queueCapacity; }
        public void setQueueCapacity(int queueCapacity) { this.queueCapacity = queueCapacity; }
        
        public String getThreadNamePrefix() { return threadNamePrefix; }
        public void setThreadNamePrefix(String threadNamePrefix) { this.threadNamePrefix = threadNamePrefix; }
        
        public Duration getKeepAliveTime() { return keepAliveTime; }
        public void setKeepAliveTime(Duration keepAliveTime) { this.keepAliveTime = keepAliveTime; }
        
        public boolean isAllowCoreThreadTimeOut() { return allowCoreThreadTimeOut; }
        public void setAllowCoreThreadTimeOut(boolean allowCoreThreadTimeOut) { this.allowCoreThreadTimeOut = allowCoreThreadTimeOut; }
    }
    
    /**
     * 缓存配置属性
     */
    public static class CacheProperties {
        /**
         * 是否启用缓存
         */
        private boolean enabled = false;
        
        /**
         * 缓存类型
         */
        private String type = "redis";
        
        /**
         * 缓存键前缀
         */
        private String keyPrefix = "logging:";
        
        /**
         * 缓存过期时间
         */
        private Duration expiry = Duration.ofHours(1);
        
        // Getters and Setters
        public boolean isEnabled() { return enabled; }
        public void setEnabled(boolean enabled) { this.enabled = enabled; }
        
        public String getType() { return type; }
        public void setType(String type) { this.type = type; }
        
        public String getKeyPrefix() { return keyPrefix; }
        public void setKeyPrefix(String keyPrefix) { this.keyPrefix = keyPrefix; }
        
        public Duration getExpiry() { return expiry; }
        public void setExpiry(Duration expiry) { this.expiry = expiry; }
    }
    
    // Main class Getters and Setters
    public boolean isEnabled() { return enabled; }
    public void setEnabled(boolean enabled) { this.enabled = enabled; }
    
    public LoggingMode getMode() { return mode; }
    public void setMode(LoggingMode mode) { this.mode = mode; }
    
    public boolean isAspectEnabled() { return aspectEnabled; }
    public void setAspectEnabled(boolean aspectEnabled) { this.aspectEnabled = aspectEnabled; }
    
    public List<String> getExcludeUrls() { return excludeUrls; }
    public void setExcludeUrls(List<String> excludeUrls) { this.excludeUrls = excludeUrls; }
    
    public List<String> getExcludeClasses() { return excludeClasses; }
    public void setExcludeClasses(List<String> excludeClasses) { this.excludeClasses = excludeClasses; }
    
    public List<String> getExcludeMethods() { return excludeMethods; }
    public void setExcludeMethods(List<String> excludeMethods) { this.excludeMethods = excludeMethods; }
    
    public DatabaseProperties getDatabase() { return database; }
    public void setDatabase(DatabaseProperties database) { this.database = database; }
    
    public FileProperties getFile() { return file; }
    public void setFile(FileProperties file) { this.file = file; }
    
    public AsyncProperties getAsync() { return async; }
    public void setAsync(AsyncProperties async) { this.async = async; }
    
    public CacheProperties getCache() { return cache; }
    public void setCache(CacheProperties cache) { this.cache = cache; }
}
